#define DDPRINTF(_f, _a...) ((void)0)
#endif
-
-
/* This may allow us to create a 'quiet' command-line option, if necessary. */
#define verbose_printf(_f, _a...) \
do { \
* in the guest's pseudophysical map.
* 0x80000000-3 mark the shared_info, and blk/net rings
*/
-#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \
- (((_mfn) < (1024*1024)) && \
- ( ( (live_mfn_to_pfn_table[_mfn] < nr_pfns) && \
- (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == (_mfn)) ) || \
-\
- (live_mfn_to_pfn_table[_mfn] >= 0x80000000 && \
- live_mfn_to_pfn_table[_mfn] <= 0x80000003 ) || \
- live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == 0x80000004 ) )
+#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \
+ (((_mfn) < (1024*1024)) && \
+ (((live_mfn_to_pfn_table[_mfn] < nr_pfns) && \
+ (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == (_mfn))) || \
+ ((live_mfn_to_pfn_table[_mfn] >= 0x80000000) && \
+ (live_mfn_to_pfn_table[_mfn] <= 0x80000003)) || \
+ (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == 0x80000004)))
/* Returns TRUE if MFN is successfully converted to a PFN. */
-#define translate_mfn_to_pfn(_pmfn) \
-({ \
- unsigned long mfn = *(_pmfn); \
- int _res = 1; \
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \
- _res = 0; \
- else \
- *(_pmfn) = live_mfn_to_pfn_table[mfn]; \
- _res; \
+#define translate_mfn_to_pfn(_pmfn) \
+({ \
+ unsigned long mfn = *(_pmfn); \
+ int _res = 1; \
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \
+ _res = 0; \
+ else \
+ *(_pmfn) = live_mfn_to_pfn_table[mfn]; \
+ _res; \
})
-
-/* test_bit */
static inline int test_bit ( int nr, volatile void * addr)
{
- return ( ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >>
- (nr % (sizeof(unsigned long)*8) ) ) & 1;
+ return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >>
+ (nr % (sizeof(unsigned long)*8))) & 1;
}
static inline void clear_bit ( int nr, volatile void * addr)
{
((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] &=
- ~(1 << (nr % (sizeof(unsigned long)*8) ) );
+ ~(1 << (nr % (sizeof(unsigned long)*8) ) );
}
static inline void set_bit ( int nr, volatile void * addr)
{
((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] |=
- (1 << (nr % (sizeof(unsigned long)*8) ) );
+ (1 << (nr % (sizeof(unsigned long)*8) ) );
}
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
+/* Returns the hamming weight (i.e. the number of bits set) in a N-bit word */
static inline unsigned int hweight32(unsigned int w)
{
- unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
- res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
- res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
- res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
- return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+ unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+ res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+ res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+ res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+ return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
}
static inline int count_bits ( int nr, volatile void *addr)
{
int i, count = 0;
unsigned long *p = (unsigned long *)addr;
- // we know the array is padded to unsigned long
+ /* We know that the array is padded to unsigned long. */
for(i=0;i<nr/(sizeof(unsigned long)*8);i++,p++)
- count += hweight32( *p );
+ count += hweight32( *p );
return count;
}
LKJIHGF
*/
- do
- {
- i = ( ( i>>(order_nr-10)) | ( i<<10 ) ) &
- ((1<<order_nr)-1);
- }
- while ( i >= nr ); // this won't ever loop if nr is a power of 2
+ do { i = ((i>>(order_nr-10)) | ( i<<10 ) ) & ((1<<order_nr)-1); }
+ while ( i >= nr ); /* this won't ever loop if nr is a power of 2 */
return i;
}
static long long tv_delta( struct timeval *new, struct timeval *old )
{
return ((new->tv_sec - old->tv_sec)*1000000 ) +
- (new->tv_usec - old->tv_usec);
+ (new->tv_usec - old->tv_usec);
}
static int print_stats( int xc_handle, u32 domid,
- int pages_sent, xc_shadow_control_stats_t *stats,
- int print )
+ int pages_sent, xc_shadow_control_stats_t *stats,
+ int print )
{
static struct timeval wall_last;
static long long d0_cpu_last;
d0_cpu_now = xc_domain_get_cpu_usage( xc_handle, 0 )/1000;
d1_cpu_now = xc_domain_get_cpu_usage( xc_handle, domid )/1000;
- if ( d0_cpu_now == -1 || d1_cpu_now == -1 )
- {
- printf("ARRHHH!!\n");
- }
+ if ( (d0_cpu_now == -1) || (d1_cpu_now == -1) )
+ printf("ARRHHH!!\n");
wall_delta = tv_delta(&wall_now,&wall_last)/1000;
d0_cpu_delta = (d0_cpu_now - d0_cpu_last)/1000;
d1_cpu_delta = (d1_cpu_now - d1_cpu_last)/1000;
- if(print)
- printf("delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, dirtied %dMb/s\n",
- wall_delta,
- (int)((d0_cpu_delta*100)/wall_delta),
- (int)((d1_cpu_delta*100)/wall_delta),
- (int)((pages_sent*PAGE_SIZE*8)/(wall_delta*1000)),
- (int)((stats->dirty_count*PAGE_SIZE*8)/(wall_delta*1000))
- );
+ if ( print )
+ printf("delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, "
+ "dirtied %dMb/s\n",
+ wall_delta,
+ (int)((d0_cpu_delta*100)/wall_delta),
+ (int)((d1_cpu_delta*100)/wall_delta),
+ (int)((pages_sent*PAGE_SIZE*8)/(wall_delta*1000)),
+ (int)((stats->dirty_count*PAGE_SIZE*8)/(wall_delta*1000)));
d0_cpu_last = d0_cpu_now;
d1_cpu_last = d1_cpu_now;
- wall_last = wall_now;
+ wall_last = wall_now;
return 0;
}
static int analysis_phase( int xc_handle, u32 domid,
- int nr_pfns, unsigned long *arr )
+ int nr_pfns, unsigned long *arr )
{
long long start, now;
xc_shadow_control_stats_t stats;
start = llgettimeofday();
- while(0)
+ while ( 0 )
{
- int i;
-
- xc_shadow_control( xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_CLEAN2,
- arr, nr_pfns, NULL);
- printf("#Flush\n");
- for(i=0;i<100;i++)
- {
- usleep(10000);
- now = llgettimeofday();
- xc_shadow_control( xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_PEEK,
- NULL, 0, &stats);
-
- printf("now= %lld faults= %ld dirty= %ld dirty_net= %ld dirty_block= %ld\n",
- ((now-start)+500)/1000,
- stats.fault_count, stats.dirty_count,
- stats.dirty_net_count, stats.dirty_block_count );
-
- }
-
-
+ int i;
+
+ xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_CLEAN2,
+ arr, nr_pfns, NULL);
+ printf("#Flush\n");
+ for ( i = 0; i < 100; i++ )
+ {
+ usleep(10000);
+ now = llgettimeofday();
+ xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_PEEK,
+ NULL, 0, &stats);
+
+ printf("now= %lld faults= %ld dirty= %ld dirty_net= %ld "
+ "dirty_block= %ld\n",
+ ((now-start)+500)/1000,
+ stats.fault_count, stats.dirty_count,
+ stats.dirty_net_count, stats.dirty_block_count);
+ }
}
-
return -1;
}
int xc_linux_save(int xc_handle,
u32 domid,
- unsigned int flags,
- int (*writerfn)(void *, const void *, size_t),
- void *writerst )
+ unsigned int flags,
+ int (*writerfn)(void *, const void *, size_t),
+ void *writerst )
{
dom0_op_t op;
int rc = 1, i, j, k, last_iter, iter = 0;
int sent_last_iter, sent_this_iter, skip_this_iter;
/* Important tuning parameters */
- int max_iters = 29; // limit us to 30 times round loop
- int max_factor = 3; // never send more than 3x nr_pfns
+ int max_iters = 29; /* limit us to 30 times round loop */
+ int max_factor = 3; /* never send more than 3x nr_pfns */
/* The new domain's shared-info frame number. */
unsigned long shared_info_frame;
if ( xc_domain_pause( xc_handle, domid ) )
{
- PERROR("Could not pause domain");
- goto out;
+ PERROR("Could not pause domain");
+ goto out;
}
if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) )
{
- PERROR("Could not get full domain info");
- goto out;
+ PERROR("Could not get full domain info");
+ goto out;
}
memcpy(name, op.u.getdomaininfo.name, sizeof(name));
shared_info_frame = op.u.getdomaininfo.shared_info_frame;
/* Map the suspend-record MFN to pin it. The page must be owned by
domid for this to succeed. */
p_srec = mfn_mapper_map_single(xc_handle, domid,
- sizeof(*p_srec), PROT_READ,
- ctxt.cpu_ctxt.esi );
+ sizeof(*p_srec), PROT_READ,
+ ctxt.cpu_ctxt.esi );
if (!p_srec)
{
/* the pfn_to_mfn_frame_list fits in a single page */
live_pfn_to_mfn_frame_list =
- mfn_mapper_map_single(xc_handle, domid,
- PAGE_SIZE, PROT_READ,
- p_srec->pfn_to_mfn_frame_list );
+ mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ p_srec->pfn_to_mfn_frame_list );
if (!live_pfn_to_mfn_frame_list)
{
/* Track the mfn_to_pfn table down from the domains PT */
{
- unsigned long *pgd;
- unsigned long mfn_to_pfn_table_start_mfn;
+ unsigned long *pgd;
+ unsigned long mfn_to_pfn_table_start_mfn;
- pgd = mfn_mapper_map_single(xc_handle, domid,
- PAGE_SIZE, PROT_READ,
- ctxt.pt_base>>PAGE_SHIFT);
+ pgd = mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ ctxt.pt_base>>PAGE_SHIFT);
- mfn_to_pfn_table_start_mfn =
- pgd[HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT]>>PAGE_SHIFT;
+ mfn_to_pfn_table_start_mfn =
+ pgd[HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT]>>PAGE_SHIFT;
- live_mfn_to_pfn_table =
- mfn_mapper_map_single(xc_handle, ~0UL,
- PAGE_SIZE*1024, PROT_READ,
- mfn_to_pfn_table_start_mfn );
+ live_mfn_to_pfn_table =
+ mfn_mapper_map_single(xc_handle, ~0UL,
+ PAGE_SIZE*1024, PROT_READ,
+ mfn_to_pfn_table_start_mfn );
}
/* Map all the frames of the pfn->mfn table. For migrate to succeed,
from a safety POV anyhow. */
live_pfn_to_mfn_table = mfn_mapper_map_batch( xc_handle, domid,
- PROT_READ,
- live_pfn_to_mfn_frame_list,
- (nr_pfns+1023)/1024 );
+ PROT_READ,
+ live_pfn_to_mfn_frame_list,
+ (nr_pfns+1023)/1024 );
if( !live_pfn_to_mfn_table )
{
PERROR("Couldn't map pfn_to_mfn table");
if( live )
{
- if ( xc_shadow_control( xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY,
- NULL, 0, NULL ) < 0 )
- {
- ERROR("Couldn't enable shadow mode");
- goto out;
- }
-
- if ( xc_domain_unpause( xc_handle, domid ) < 0 )
- {
- ERROR("Couldn't unpause domain");
- goto out;
- }
-
- last_iter = 0;
- sent_last_iter = 1<<20; // 4GB's worth of pages
+ if ( xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY,
+ NULL, 0, NULL ) < 0 )
+ {
+ ERROR("Couldn't enable shadow mode");
+ goto out;
+ }
+
+ if ( xc_domain_unpause( xc_handle, domid ) < 0 )
+ {
+ ERROR("Couldn't unpause domain");
+ goto out;
+ }
+
+ last_iter = 0;
+ sent_last_iter = 1<<20; /* 4GB of pages */
}
else
- last_iter = 1;
+ last_iter = 1;
/* calculate the power of 2 order of nr_pfns, e.g.
- 15->4 16->4 17->5 */
+ 15->4 16->4 17->5 */
for( i=nr_pfns-1, order_nr=0; i ; i>>=1, order_nr++ );
/* Setup to_send bitmap */
{
- int sz = (nr_pfns/8) + 8; // includes slop at end of array
-
- to_send = malloc( sz );
- to_fix = calloc( 1, sz );
- to_skip = malloc( sz );
-
- if (!to_send || !to_fix || !to_skip)
- {
- ERROR("Couldn't allocate to_send array");
- goto out;
- }
-
- memset( to_send, 0xff, sz );
-
- if ( mlock( to_send, sz ) )
- {
- PERROR("Unable to mlock to_send");
- return 1;
- }
-
- /* (to fix is local only) */
-
- if ( mlock( to_skip, sz ) )
- {
- PERROR("Unable to mlock to_skip");
- return 1;
- }
+ int sz = (nr_pfns/8) + 8; /* includes slop at end of array */
+
+ to_send = malloc( sz );
+ to_fix = calloc( 1, sz );
+ to_skip = malloc( sz );
+
+ if (!to_send || !to_fix || !to_skip)
+ {
+ ERROR("Couldn't allocate to_send array");
+ goto out;
+ }
+
+ memset( to_send, 0xff, sz );
+
+ if ( mlock( to_send, sz ) )
+ {
+ PERROR("Unable to mlock to_send");
+ return 1;
+ }
+
+ /* (to fix is local only) */
+
+ if ( mlock( to_skip, sz ) )
+ {
+ PERROR("Unable to mlock to_skip");
+ return 1;
+ }
}
if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) )
{
- ERROR("Unable to mlock");
- goto out;
+ ERROR("Unable to mlock");
+ goto out;
}
{
mfn = live_pfn_to_mfn_table[i];
- if( (live_mfn_to_pfn_table[mfn] != i) && (mfn != 0x80000004) )
- printf("i=0x%x mfn=%x live_mfn_to_pfn_table=%x\n",
- i,mfn,live_mfn_to_pfn_table[mfn]);
+ if( (live_mfn_to_pfn_table[mfn] != i) && (mfn != 0x80000004) )
+ printf("i=0x%x mfn=%x live_mfn_to_pfn_table=%x\n",
+ i,mfn,live_mfn_to_pfn_table[mfn]);
}
#endif
/* Map the shared info frame */
live_shinfo = mfn_mapper_map_single(xc_handle, domid,
- PAGE_SIZE, PROT_READ,
- shared_info_frame);
+ PAGE_SIZE, PROT_READ,
+ shared_info_frame);
if (!live_shinfo)
{
while(1)
{
- unsigned int prev_pc, sent_this_iter, N, batch;
-
- iter++;
- sent_this_iter = 0;
- skip_this_iter = 0;
- prev_pc = 0;
- N=0;
-
- verbose_printf("Saving memory pages: iter %d 0%%", iter);
-
- while( N < nr_pfns )
- {
- unsigned int this_pc = (N * 100) / nr_pfns;
-
- if ( (this_pc - prev_pc) >= 5 )
- {
- verbose_printf("\b\b\b\b%3d%%", this_pc);
- prev_pc = this_pc;
- }
-
- /* slightly wasteful to peek the whole array evey time,
- but this is fast enough for the moment. */
-
- if ( !last_iter &&
- xc_shadow_control(xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_PEEK,
- to_skip, nr_pfns, NULL) != nr_pfns )
- {
- ERROR("Error peeking shadow bitmap");
- goto out;
- }
-
-
- /* load pfn_type[] with the mfn of all the pages we're doing in
- this batch. */
-
- for( batch = 0; batch < BATCH_SIZE && N < nr_pfns ; N++ )
- {
- int n = permute(N, nr_pfns, order_nr );
-
- if(0 && debug)
- fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d [mfn]= %08lx\n",
- iter, n, live_pfn_to_mfn_table[n],
- test_bit(n,to_send),
- live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]&0xFFFFF]);
-
- if (!last_iter && test_bit(n, to_send) && test_bit(n, to_skip))
- skip_this_iter++; // stats keeping
-
- if (! ( (test_bit(n, to_send) && !test_bit(n, to_skip)) ||
- (test_bit(n, to_send) && last_iter) ||
- (test_bit(n, to_fix) && last_iter) ) )
- continue;
-
- /* we get here if:
- 1. page is marked to_send & hasn't already been re-dirtied
- 2. (ignore to_skip in last iteration)
- 3. add in pages that still need fixup (net bufs)
- */
-
- pfn_batch[batch] = n;
- pfn_type[batch] = live_pfn_to_mfn_table[n];
-
- if( pfn_type[batch] == 0x80000004 )
- {
- /* not currently in pusedo-physical map -- set bit
- in to_fix that we must send this page in last_iter
- unless its sent sooner anyhow */
-
- set_bit( n, to_fix );
- if( iter>1 )
- DDPRINTF("Urk! netbuf race: iter %d, pfn %lx. mfn %lx\n",
- iter,n,pfn_type[batch]);
- continue;
- }
-
- if ( last_iter && test_bit(n, to_fix ) && !test_bit(n, to_send ))
- {
- needed_to_fix++;
- DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n",
- iter,n,pfn_type[batch]);
- }
-
- clear_bit( n, to_fix );
-
- batch++;
- }
-
- DDPRINTF("batch %d:%d (n=%d)\n",iter,batch,n);
-
- if(batch == 0) goto skip; // vanishingly unlikely...
-
- if ( (region_base = mfn_mapper_map_batch( xc_handle, domid,
- PROT_READ,
- pfn_type,
- batch )) == 0)
- {
- PERROR("map batch failed");
- goto out;
- }
-
- if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) )
- {
- ERROR("get_pfn_type_batch failed");
- goto out;
- }
-
- for( j = 0; j < batch; j++ )
- {
- if( (pfn_type[j] & LTAB_MASK) == XTAB)
- {
- DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]);
- continue;
- }
-
- if(0 && debug)
- fprintf(stderr,"%d pfn= %08lx mfn= %08lx [mfn]= %08lx sum= %08lx\n",
- iter,
- (pfn_type[j] & LTAB_MASK) | pfn_batch[j],
- pfn_type[j],
- live_mfn_to_pfn_table[pfn_type[j]&(~LTAB_MASK)],
- csum_page(region_base + (PAGE_SIZE*j))
- );
-
- /* canonicalise mfn->pfn */
- pfn_type[j] = (pfn_type[j] & LTAB_MASK) |
- pfn_batch[j];
- //live_mfn_to_pfn_table[pfn_type[j]&~LTAB_MASK];
-
- }
-
-
- if ( (*writerfn)(writerst, &batch, sizeof(int) ) )
- {
- ERROR("Error when writing to state file (2)");
- goto out;
- }
-
- if ( (*writerfn)(writerst, pfn_type, sizeof(unsigned long)*j ) )
- {
- ERROR("Error when writing to state file (3)");
- goto out;
- }
-
- /* entering this loop, pfn_type is now in pfns (Not mfns) */
- for( j = 0; j < batch; j++ )
- {
- /* write out pages in batch */
-
- if( (pfn_type[j] & LTAB_MASK) == XTAB)
- {
- DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]);
- continue;
- }
-
- if ( ((pfn_type[j] & LTAB_MASK) == L1TAB) ||
- ((pfn_type[j] & LTAB_MASK) == L2TAB) )
- {
-
- memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE);
-
- for ( k = 0;
- k < (((pfn_type[j] & LTAB_MASK) == L2TAB) ?
- (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) : 1024);
- k++ )
- {
- unsigned long pfn;
-
- if ( !(page[k] & _PAGE_PRESENT) ) continue;
- mfn = page[k] >> PAGE_SHIFT;
- pfn = live_mfn_to_pfn_table[mfn];
-
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
- {
- // I don't think this should ever happen
-
- printf("FNI %d : [%08lx,%d] pte=%08lx, mfn=%08lx, pfn=%08lx [mfn]=%08lx\n",
- j, pfn_type[j], k,
- page[k], mfn, live_mfn_to_pfn_table[mfn],
- (live_mfn_to_pfn_table[mfn]<nr_pfns)?
- live_pfn_to_mfn_table[live_mfn_to_pfn_table[mfn]]: 0xdeadbeef);
-
- pfn = 0; // be suspicious, very suspicious
-
- //goto out; // let's try our luck
-
-
- }
- page[k] &= PAGE_SIZE - 1;
- page[k] |= pfn << PAGE_SHIFT;
-
-#if 0
- printf("L%d i=%d pfn=%d mfn=%d k=%d pte=%08lx xpfn=%d\n",
- pfn_type[j]>>28,
- j,i,mfn,k,page[k],page[k]>>PAGE_SHIFT);
-#endif
-
- } /* end of page table rewrite for loop */
-
- if ( (*writerfn)(writerst, page, PAGE_SIZE) )
- {
- ERROR("Error when writing to state file (4)");
- goto out;
- }
-
- } /* end of it's a PT page */
- else
- { /* normal page */
-
- if ( (*writerfn)(writerst, region_base + (PAGE_SIZE*j), PAGE_SIZE) )
- {
- ERROR("Error when writing to state file (5)");
- goto out;
- }
- }
- } /* end of the write out for this batch */
-
- sent_this_iter += batch;
-
- } /* end of this while loop for this iteration */
-
- munmap(region_base, batch*PAGE_SIZE);
+ unsigned int prev_pc, sent_this_iter, N, batch;
- skip:
+ iter++;
+ sent_this_iter = 0;
+ skip_this_iter = 0;
+ prev_pc = 0;
+ N=0;
- total_sent += sent_this_iter;
+ verbose_printf("Saving memory pages: iter %d 0%%", iter);
- verbose_printf("\r %d: sent %d, skipped %d, ",
- iter, sent_this_iter, skip_this_iter );
+ while( N < nr_pfns )
+ {
+ unsigned int this_pc = (N * 100) / nr_pfns;
+
+ if ( (this_pc - prev_pc) >= 5 )
+ {
+ verbose_printf("\b\b\b\b%3d%%", this_pc);
+ prev_pc = this_pc;
+ }
+
+ /* slightly wasteful to peek the whole array evey time,
+ but this is fast enough for the moment. */
+
+ if ( !last_iter &&
+ xc_shadow_control(xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_PEEK,
+ to_skip, nr_pfns, NULL) != nr_pfns )
+ {
+ ERROR("Error peeking shadow bitmap");
+ goto out;
+ }
+
- if ( last_iter )
- {
- print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
+ /* load pfn_type[] with the mfn of all the pages we're doing in
+ this batch. */
+
+ for ( batch = 0; batch < BATCH_SIZE && N < nr_pfns ; N++ )
+ {
+ int n = permute(N, nr_pfns, order_nr );
+
+ if ( 0 && debug )
+ fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d "
+ " [mfn]= %08lx\n",
+ iter, n, live_pfn_to_mfn_table[n],
+ test_bit(n,to_send),
+ live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]&
+ 0xFFFFF]);
+
+ if ( !last_iter &&
+ test_bit(n, to_send) &&
+ test_bit(n, to_skip) )
+ skip_this_iter++; /* stats keeping */
+
+ if ( !((test_bit(n, to_send) && !test_bit(n, to_skip)) ||
+ (test_bit(n, to_send) && last_iter) ||
+ (test_bit(n, to_fix) && last_iter)) )
+ continue;
+
+ /* we get here if:
+ 1. page is marked to_send & hasn't already been re-dirtied
+ 2. (ignore to_skip in last iteration)
+ 3. add in pages that still need fixup (net bufs)
+ */
+
+ pfn_batch[batch] = n;
+ pfn_type[batch] = live_pfn_to_mfn_table[n];
+
+ if( pfn_type[batch] == 0x80000004 )
+ {
+ /* not currently in pusedo-physical map -- set bit
+ in to_fix that we must send this page in last_iter
+ unless its sent sooner anyhow */
+
+ set_bit( n, to_fix );
+ if( iter>1 )
+ DDPRINTF("netbuf race: iter %d, pfn %lx. mfn %lx\n",
+ iter,n,pfn_type[batch]);
+ continue;
+ }
+
+ if ( last_iter &&
+ test_bit(n, to_fix) &&
+ !test_bit(n, to_send) )
+ {
+ needed_to_fix++;
+ DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n",
+ iter,n,pfn_type[batch]);
+ }
+
+ clear_bit(n, to_fix);
+
+ batch++;
+ }
+
+ DDPRINTF("batch %d:%d (n=%d)\n", iter, batch, n);
+
+ if ( batch == 0 )
+ goto skip; /* vanishingly unlikely... */
+
+ if ( (region_base = mfn_mapper_map_batch(xc_handle, domid,
+ PROT_READ,
+ pfn_type,
+ batch)) == 0 )
+ {
+ PERROR("map batch failed");
+ goto out;
+ }
+
+ if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) )
+ {
+ ERROR("get_pfn_type_batch failed");
+ goto out;
+ }
+
+ for ( j = 0; j < batch; j++ )
+ {
+ if ( (pfn_type[j] & LTAB_MASK) == XTAB )
+ {
+ DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]);
+ continue;
+ }
+
+ if ( 0 && debug )
+ fprintf(stderr, "%d pfn= %08lx mfn= %08lx [mfn]= %08lx"
+ " sum= %08lx\n",
+ iter,
+ (pfn_type[j] & LTAB_MASK) | pfn_batch[j],
+ pfn_type[j],
+ live_mfn_to_pfn_table[pfn_type[j]&(~LTAB_MASK)],
+ csum_page(region_base + (PAGE_SIZE*j)));
+
+ /* canonicalise mfn->pfn */
+ pfn_type[j] = (pfn_type[j] & LTAB_MASK) | pfn_batch[j];
+ }
+
+ if ( (*writerfn)(writerst, &batch, sizeof(int) ) )
+ {
+ ERROR("Error when writing to state file (2)");
+ goto out;
+ }
+
+ if ( (*writerfn)(writerst, pfn_type, sizeof(unsigned long)*j ) )
+ {
+ ERROR("Error when writing to state file (3)");
+ goto out;
+ }
+
+ /* entering this loop, pfn_type is now in pfns (Not mfns) */
+ for( j = 0; j < batch; j++ )
+ {
+ /* write out pages in batch */
+ if( (pfn_type[j] & LTAB_MASK) == XTAB)
+ {
+ DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]);
+ continue;
+ }
+
+ if ( ((pfn_type[j] & LTAB_MASK) == L1TAB) ||
+ ((pfn_type[j] & LTAB_MASK) == L2TAB) )
+ {
+ memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE);
+
+ for ( k = 0;
+ k < (((pfn_type[j] & LTAB_MASK) == L2TAB) ?
+ (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) :
+ 1024);
+ k++ )
+ {
+ unsigned long pfn;
+
+ if ( !(page[k] & _PAGE_PRESENT) )
+ continue;
+
+ mfn = page[k] >> PAGE_SHIFT;
+ pfn = live_mfn_to_pfn_table[mfn];
+
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
+ {
+ /* I don't think this should ever happen */
+ printf("FNI %d : [%08lx,%d] pte=%08lx, "
+ "mfn=%08lx, pfn=%08lx [mfn]=%08lx\n",
+ j, pfn_type[j], k,
+ page[k], mfn, live_mfn_to_pfn_table[mfn],
+ (live_mfn_to_pfn_table[mfn]<nr_pfns)?
+ live_pfn_to_mfn_table[
+ live_mfn_to_pfn_table[mfn]] :
+ 0xdeadbeef);
+
+ pfn = 0; /* be suspicious */
+ }
+
+ page[k] &= PAGE_SIZE - 1;
+ page[k] |= pfn << PAGE_SHIFT;
+
+#if 0
+ printf("L%d i=%d pfn=%d mfn=%d k=%d pte=%08lx "
+ "xpfn=%d\n",
+ pfn_type[j]>>28,
+ j,i,mfn,k,page[k],page[k]>>PAGE_SHIFT);
+#endif
+
+ } /* end of page table rewrite for loop */
+
+ if ( (*writerfn)(writerst, page, PAGE_SIZE) )
+ {
+ ERROR("Error when writing to state file (4)");
+ goto out;
+ }
+
+ } /* end of it's a PT page */
+ else
+ { /* normal page */
+
+ if ( (*writerfn)(writerst, region_base + (PAGE_SIZE*j),
+ PAGE_SIZE) )
+ {
+ ERROR("Error when writing to state file (5)");
+ goto out;
+ }
+ }
+ } /* end of the write out for this batch */
+
+ sent_this_iter += batch;
- verbose_printf("Total pages sent= %d (%.2fx)\n",
- total_sent, ((float)total_sent)/nr_pfns );
- verbose_printf("(of which %d were fixups)\n", needed_to_fix );
- }
+ } /* end of this while loop for this iteration */
- if ( debug && last_iter )
- {
- int minusone = -1;
- memset( to_send, 0xff, (nr_pfns+8)/8 );
- debug = 0;
- printf("Entering debug resend-all mode\n");
-
- /* send "-1" to put receiver into debug mode */
- if ( (*writerfn)(writerst, &minusone, sizeof(int)) )
- {
- ERROR("Error when writing to state file (6)");
- goto out;
- }
+ munmap(region_base, batch*PAGE_SIZE);
- continue;
- }
+ skip:
- if ( last_iter )
- break;
+ total_sent += sent_this_iter;
- if ( live )
- {
- if (
- // ( sent_this_iter > (sent_last_iter * 0.95) ) ||
- (iter >= max_iters) ||
- (sent_this_iter+skip_this_iter < 50) ||
- (total_sent > nr_pfns*max_factor) )
- {
- DPRINTF("Start last iteration\n");
- last_iter = 1;
+ verbose_printf("\r %d: sent %d, skipped %d, ",
+ iter, sent_this_iter, skip_this_iter );
- xc_domain_pause( xc_handle, domid );
+ if ( last_iter )
+ {
+ print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
- }
+ verbose_printf("Total pages sent= %d (%.2fx)\n",
+ total_sent, ((float)total_sent)/nr_pfns );
+ verbose_printf("(of which %d were fixups)\n", needed_to_fix );
+ }
- if ( xc_shadow_control( xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_CLEAN2,
- to_send, nr_pfns, &stats ) != nr_pfns )
- {
- ERROR("Error flushing shadow PT");
- goto out;
- }
+ if ( debug && last_iter )
+ {
+ int minusone = -1;
+ memset( to_send, 0xff, (nr_pfns+8)/8 );
+ debug = 0;
+ printf("Entering debug resend-all mode\n");
+
+ /* send "-1" to put receiver into debug mode */
+ if ( (*writerfn)(writerst, &minusone, sizeof(int)) )
+ {
+ ERROR("Error when writing to state file (6)");
+ goto out;
+ }
+
+ continue;
+ }
- sent_last_iter = sent_this_iter;
+ if ( last_iter )
+ break;
- print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
-
- }
+ if ( live )
+ {
+ if (
+ /* ( sent_this_iter > (sent_last_iter * 0.95) ) || */
+ (iter >= max_iters) ||
+ (sent_this_iter+skip_this_iter < 50) ||
+ (total_sent > nr_pfns*max_factor) )
+ {
+ DPRINTF("Start last iteration\n");
+ last_iter = 1;
+
+ xc_domain_pause( xc_handle, domid );
+ }
+
+ if ( xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_CLEAN2,
+ to_send, nr_pfns, &stats ) != nr_pfns )
+ {
+ ERROR("Error flushing shadow PT");
+ goto out;
+ }
+
+ sent_last_iter = sent_this_iter;
+
+ print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
+
+ }
} /* end of while 1 */
/* Zero terminate */
if ( (*writerfn)(writerst, &rc, sizeof(int)) )
{
- ERROR("Error when writing to state file (6)");
- goto out;
+ ERROR("Error when writing to state file (6)");
+ goto out;
}
/* Get the final execution context */
if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) )
{
- PERROR("Could not get full domain info");
- goto out;
+ PERROR("Could not get full domain info");
+ goto out;
}
/* Canonicalise the suspend-record frame number. */
ERROR("PT base is not in range of pseudophys map");
goto out;
}
- ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] << PAGE_SHIFT;
+ ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] <<
+ PAGE_SHIFT;
- if ( (*writerfn)(writerst, &ctxt, sizeof(ctxt)) ||
- (*writerfn)(writerst, live_shinfo, PAGE_SIZE) )
+ if ( (*writerfn)(writerst, &ctxt, sizeof(ctxt)) ||
+ (*writerfn)(writerst, live_shinfo, PAGE_SIZE) )
{
ERROR("Error when writing to state file (1)");
goto out;
}
munmap(live_shinfo, PAGE_SIZE);
-out:
+ out:
if ( pfn_type != NULL )
free(pfn_type);